﻿using System;
using System.Collections.Generic;
using System.Linq;
using MWS.Processing.Interfaces;
using MWS.Processing.Processors;
using ThrottledProcessing.SampleApplication.Domain;
using ThrottledProcessing.SampleApplication.Interfaces;
using ThrottledProcessing.SampleApplication.Messages;
using ThrottledProcessing.SampleApplication.Services;

namespace ThrottledProcessing.SampleApplication.Processors
{
    public class UpcomingBillEventEnqueueProcessor :
        EnqueueProcessor<GetUpcomingBillsRequest, GetUpcomingBillsResponse, ProcessEventRequest>
    {
        private readonly ILoggingService loggingService;


        public UpcomingBillEventEnqueueProcessor(ILoggingService loggingService, IQueue<ProcessEventRequest> queue)
            : this(queue, new BillPaymentService(loggingService), loggingService)
        {
        }

        public UpcomingBillEventEnqueueProcessor(IQueue<ProcessEventRequest> queue,
                                                 IBillPaymentService billPaymentService,
                                                 ILoggingService loggingService) :
                                                     base(billPaymentService.GetUpcomingBills, queue)
        {
            this.loggingService = loggingService;
            Error += OnError;
            Stopping += OnStoppingLocal;
            Stopped += OnStopped;

            for (var i = 0; i < 100; i++)
                userLastQueried.Add(i, DateTime.MinValue);
        }


        public override IList<GetUpcomingBillsRequest> GetRequests(int maxRequests)
        {
            loggingService.Debug("Getting requests...");
            var users = userLastQueried
                .Where(user => user.Value == DateTime.MinValue).Take(maxRequests);

            var requests = users.Select(user => new GetUpcomingBillsRequest
                                                    {
                                                        UserId = user.Key.ToString()
                                                    }).ToList();

            users.ToList().ForEach(user => userLastQueried[user.Key] = DateTime.Now);

            return requests;
        }

        public override IList<ProcessEventRequest> GetQueueRequests(GetUpcomingBillsRequest request,
                                                                    GetUpcomingBillsResponse response)
        {
            var events = new List<ProcessEventRequest>();

            loggingService.Debug(string.Format("Got response for userId {0}. Sending event now.", request.UserId));

            // Record the last time he user has been processed.
            userLastQueried[Convert.ToInt32(request.UserId)] = DateTime.Now;

            response.UpcomingBills.ForEach(bill =>
                                           events.Add(
                                               new ProcessEventRequest
                                                   {
                                                       UserId = request.UserId,
                                                       Event = new UpcomingBillDueEvent
                                                                   {
                                                                       EventId = Guid.NewGuid().ToString(),
                                                                       Bill = bill
                                                                   }
                                                   }));
            return events;
        }

        private void OnError(object sender, ErrorEventArgs args)
        {
            loggingService.Error(string.Format("Got an error while processing userId {0}, Exception: {1}",
                                               args.Request.UserId, args.Exception.Message));
        }

        private void OnStoppingLocal(object sender, StatusChangedEventArgs args)
        {
            loggingService.Debug("============ STOPPING UPCOMING BILL EVENT SERVICE! ===========");
        }

        private void OnStopped(object sender, StatusChangedEventArgs args)
        {
            loggingService.Debug("==== STOPPED BILL SERVICE ===");
        }

        private readonly Dictionary<int, DateTime> userLastQueried = new Dictionary<int, DateTime>();
    }
}